/**
 * Copyright 2011 Marco Berri - marcoberri@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 */
package com.mbfasttrack.controller;

import com.mbfasttrack.model.Like;
import com.mbfasttrack.model.User;
import com.mbfasttrack.service.UserService;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Properties;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServletResponse;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * @author Marco Berri marcoberri@gmail.com http://tecnicume.blogspot.com
 */
@Controller
public class UserController extends Base {


    /**
     *
     */
    @Value("${sys.site.testmail}")
    public String sys_site_testmail;
    /**
     *
     */
    @Value("${sys.site.email.from}")
    public String sys_site_email_from;
    /**
     *
     */
    @Value("${sys.site.email.admin}")
    public String sys_site_email_admin;
    /**
     *
     */
    @Value("${sys.site.email.host}")
    public String sys_site_email_host;

    /**
     *
     * @return
     */
    @ModelAttribute("user")
    public User getUserObject() {
        return new User();
    }

    /**
     *
     * @param userService
     */
    @Autowired(required = true)
    public void setUserService(UserService userService) {
        this.userService = userService;

    }

    /**
     *
     * @param user
     * @param model
     * @return
     * @throws MessagingException
     */
    @RequestMapping(value = "/user/save", method = RequestMethod.POST)
    public String Save(@ModelAttribute("user") User user, Model model) throws MessagingException {


        user.setConfirmRegistration(Boolean.FALSE);
        user = userService.add(user);


        if (user == null) {
            model.addAttribute("error", "site.user.form.submit.error.username.exists");
            return "/user/error";
        }

        actionService.add(user.getUsername(), user);

        sendMail(user);
        model.addAttribute("output", "user: " + user);
        return "user/saveresult";
    }

    /**
     * Dettaglio del tracciato
     *
     * @param username
     * @param model
     * @return
     */
    @RequestMapping(value = "/user/like/{username}", method = RequestMethod.GET)
    public String addFriend(@PathVariable String username, Model model) {

        if (isGuest()) {
            return "redirect:/login";
        }

        User usertolike = userService.userRepository.findOneByUsername(username);

        org.springframework.security.core.userdetails.User u = (org.springframework.security.core.userdetails.User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        User user = userService.userRepository.findOneByUsername(u.getUsername());
        Like l = likeService.add(usertolike, user, Boolean.TRUE);
        actionService.add(u.getUsername(), l, usertolike);
        return "response/ok";
    }

    /**
     * modifica dell'utente
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/user/modify", method = RequestMethod.GET)
    public String getDetails(Model model) {



        if (isGuest()) {
            return "redirect:/login";
        }

        org.springframework.security.core.userdetails.User u = (org.springframework.security.core.userdetails.User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        model = this.getBaseModel(model);
        User user = userService.userRepository.findOneByUsername(u.getUsername());
        model.addAttribute("user", user);
        return "user/add";
    }

    /**
     *
     * @param username
     * @param model
     * @return
     */
    @RequestMapping(value = "/dashboard/{username}")
    public String getStream(@PathVariable String username, Model model) {

        model = this.getBaseModel(model);

        try {
            User user = userService.userRepository.findOneByUsername(username);
            model.addAttribute("stream", actionService.getAllByUserId(user.getId()));
            model.addAttribute("tracks", trackService.getAllByUserId(user.getId()));
            model.addAttribute("activity", trackService.getDistinctCountActivityByUserId(user.getId()));
            model.addAttribute("user", user);
            model.addAttribute("friends", userService.findFriendByUserId(user.getId()));
            model.addAttribute("dashboardpublic", user.getDashboardPublic());

            //verifico che ci siano persone vicino a me cerco fino a 100 km.
            Page<User> near = userService.getUsersNearMe(username, 100);


            if (near != null || near.hasContent()) {
                model.addAttribute("usernear", near);
            }




        } catch (Exception e) {
        }
        return "user/dashboard";
    }

    /**
     * Intercetta l'utente loggato e lo butta sulla propria dashboard
     *
     * @param model
     * @return
     */
    @RequestMapping(value = "/dashboard")
    public String getMyStream(Model model) {

        if (isGuest()) {
            return "redirect:/login";
        }

        org.springframework.security.core.userdetails.User u = (org.springframework.security.core.userdetails.User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        return this.getStream(u.getUsername(), model);

    }

    /**
     *
     * @param userid
     * @param model
     * @return
     */
    @RequestMapping(value = "/user/{userid}/confirm")
    public String confirm(@PathVariable String userid, Model model) {



        User user = userService.userRepository.findOneById(userid);

        if (user == null) {
            model.addAttribute("error", "site.user.form.submit.error.username.notexists");
            return "/user/error";
        }

        if (user.getConfirmRegistration() == Boolean.TRUE) {
            model.addAttribute("error", "site.user.form.submit.error.username.alreadyconfirmed");
            return "/user/error";
        }

        user.setConfirmRegistration(Boolean.TRUE);
        userService.save(user);


        model.addAttribute("output", "user: " + user);
        return "user/saveresult";
    }

    /**
     * QUESTA FUNZIONE è DA CAPIRE, NON MI PIACE PER UN TUBO...
     *
     * @param user
     * @param model
     * @return
     * @throws MessagingException
     */
    @RequestMapping(value = "/user/modify/save", method = RequestMethod.POST)
    public String processSubmitModify(@ModelAttribute("user") User user, Model model) throws MessagingException {

        if (isGuest()) {
            return "redirect:/login";
        }

        org.springframework.security.core.userdetails.User u = (org.springframework.security.core.userdetails.User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();


        User user_loaded = userService.userRepository.findOneByUsername(u.getUsername());

        user_loaded.setFirstname(user.getFirstname());
        user_loaded.setLastname(user.getLastname());

        if (user.getFirstnamePublic().booleanValue() == true) {
            user_loaded.setFirstnamePublic(user.getFirstnamePublic());
        } else {
            user_loaded.setFirstnamePublic(false);
        }

        if (user.getLastnamePublic().booleanValue() == true) {
            user_loaded.setLastnamePublic(user.getLastnamePublic());
        } else {
            user_loaded.setLastnamePublic(false);
        }

        if (user.getLocationPublic().booleanValue() == true) {
            user_loaded.setLocationPublic(user.getLocationPublic());
        } else {
            user_loaded.setLocationPublic(false);
        }


        if (user.getEmailPublic().booleanValue() == true) {
            user_loaded.setEmailPublic(user.getEmailPublic());
        } else {
            user_loaded.setEmailPublic(false);
        }

        if (user.getDashboardPublic().booleanValue() == true) {
            user_loaded.setDashboardPublic(user.getDashboardPublic());
        } else {
            user_loaded.setDashboardPublic(false);
        }

        if (user.getAvatar() != null) {
            user_loaded.setAvatar(user.getAvatar());
        }

        System.err.println("start save user: " + user_loaded);
        userService.save(user_loaded);

        return "redirect:/dashboard";
    }

    /**
     * Json con il risultato per le autocomplete
     *
     * @param username
     * @param response
     * @throws JsonGenerationException
     * @throws JsonMappingException
     * @throws IOException
     */
    @RequestMapping(value = "/user/json/usernameexists", method = RequestMethod.GET)
    public void jsonSearchUsername(@RequestParam("username") String username, HttpServletResponse response) throws JsonGenerationException, JsonMappingException, IOException {

        User u = userService.userRepository.findOneByUsername(username.toLowerCase());

        ObjectMapper mapper = new ObjectMapper();

        HashMap result = new HashMap();
        result.put("usernameexists", (u == null ? false : true));

        String jsonString = mapper.writeValueAsString(result);

        AbstractHttpMessageConverter<String> stringHttpMessageConverter = new StringHttpMessageConverter();

        MediaType jsonMimeType = MediaType.APPLICATION_JSON;

        if (stringHttpMessageConverter.canWrite(String.class, jsonMimeType)) {

            try {

                stringHttpMessageConverter.write(jsonString, jsonMimeType, new ServletServerHttpResponse(response));

            } catch (Exception e) {
                log.fatal(e);
                System.err.print("exception " + e.getMessage());
            }

        }

    }

    @RequestMapping(value = "/user/json/emailexists", method = RequestMethod.GET)
    public void jsonSearchEmail(@RequestParam("email") String email, HttpServletResponse response) throws JsonGenerationException, JsonMappingException, IOException {
        try {
            User u = userService.userRepository.findOneByEmail(email.toLowerCase());

            ObjectMapper mapper = new ObjectMapper();

            HashMap result = new HashMap();
            result.put("emailexists", (u == null ? false : true));

            String jsonString = mapper.writeValueAsString(result);

            AbstractHttpMessageConverter<String> stringHttpMessageConverter = new StringHttpMessageConverter();

            MediaType jsonMimeType = MediaType.APPLICATION_JSON;

            if (stringHttpMessageConverter.canWrite(String.class, jsonMimeType)) {
                stringHttpMessageConverter.write(jsonString, jsonMimeType, new ServletServerHttpResponse(response));
            }


        } catch (Exception e) {
            log.fatal(e);

        }

    }

    /**
     *
     * @param user
     * @return
     * @throws MessagingException
     */
    public boolean sendMail(User user) throws MessagingException {



        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        String path = requestAttributes.getRequest().getRealPath("/");



        Properties p = new Properties();
        p.setProperty("file.resource.loader.path", path + "/WEB-INF/email/");
        p.setProperty("file.resource.loader.cache", "true");
        p.setProperty("file.resource.loader.modificationCheckInterval", "2");

        Velocity.init(p);


        VelocityContext c = new VelocityContext();
        c.put("user", user);
        c.put("path", sys_site_url);


        Template template = Velocity.getTemplate("confermaregistrazione_text.vm");
        StringWriter text = new StringWriter();
        template.setEncoding("UTF8");
        template.merge(c, text);


        template = Velocity.getTemplate("confermaregistrazione_html.vm");
        StringWriter html = new StringWriter();
        template.setEncoding("UTF8");
        template.merge(c, html);



        JavaMailSenderImpl sender = new JavaMailSenderImpl();
        sender.setHost(sys_site_email_host);


        MimeMessage message = sender.createMimeMessage();

        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        if (this.sys_site_testmail != null && "".equalsIgnoreCase(this.sys_site_testmail)) {

            helper.setTo(this.sys_site_testmail);

        } else {

            helper.setTo(user.getEmail());
            helper.setBcc(this.sys_site_email_admin);

        }

        helper.setFrom(this.sys_site_email_from);
        helper.setSubject("registrazione");

        helper.setText("" + text, "" + html);

        sender.send(message);



        return true;
    }
}